package com.example.listen;


import com.example.bean.NetInfo;
import com.example.service.CLibrary;
import com.example.service.DeviceService;
import com.example.util.EStringUtil;
import com.example.util.TypeConversionUtil;
import com.sun.jna.ptr.IntByReference;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.xml.bind.DatatypeConverter;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.file.Paths;
import java.util.concurrent.*;

@Component
@Slf4j
public class TCPServer {

    public static final Integer port=8000;

    public static final String CHECK_HEADER="HS";

    public static final Integer SOCKET_TIMEOUT = 60*1000; // 1分钟超时
    public static final Integer CONNECTION_TIMEOUT = 3000; // 连接超时3秒

    public static  Integer  jishu=1;

    @Value("${library.com.read.path}")
    private String libraryComReadPath;
    @Value("${library.com.hidapi.path}")
    private String libraryComHidapiPath;


    @Autowired
    DeviceService deviceService;

    //static ExecutorService executorService = Executors.newCachedThreadPool();
    static ExecutorService executorService = Executors.newFixedThreadPool(65); // 假设最大线程数为 65
    // 使用可配置的线程池
    /*static ExecutorService executorService = new ThreadPoolExecutor(
            10, // 核心线程数
            100, // 最大线程数
            60L, TimeUnit.SECONDS, // 空闲线程超时时间
            new LinkedBlockingQueue<>(1000), // 任务队列大小
            new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
    );*/

    @PostConstruct
    public void readCardInfo() {
        try {
            System.load(libraryComHidapiPath);
            System.load(libraryComReadPath);
            log.info("DLL loaded successfully from: {}", libraryComReadPath);
        } catch (UnsatisfiedLinkError e) {
            log.error("Failed to load DLL: {}", e.getMessage(), e);
            throw new RuntimeException("Unable to load DLL: " + e.getMessage(), e);
        }

        CompletableFuture.runAsync(() -> {
            try (ServerSocket serverSocket = new ServerSocket(port)) {
                serverSocket.setReuseAddress(true); // 允许地址重用
                log.info("TCP server listening on port {}", port);

                while (true) {
                    // 接受客户端连接
                    Socket clientSocket = serverSocket.accept();
                    log.info("New TCP connection established from {}", clientSocket.getInetAddress());

                    // 提交任务到线程池处理
                    executorService.submit(() -> handleClient(clientSocket));
                }
            } catch (IOException ex) {
                if (!executorService.isShutdown()) {
                    log.error("ServerSocket error: {}", ex.getMessage(), ex);
                }
            }
        });
    }

    private void configureSocket(Socket socket) throws IOException {
        socket.setSoTimeout(SOCKET_TIMEOUT); // 设置读取超时
        socket.setKeepAlive(true); // 启用TCP保活机制
        socket.setTcpNoDelay(true); // 禁用Nagle算法，减少延迟
        socket.setSoLinger(true, 5); // 设置优雅关闭时间
    }

    /*private void handleClient(Socket socket) {
        try (
                InputStream input = socket.getInputStream();
        ) {
            byte[] buffer = new byte[1024]; // 缓冲区
            int bytesRead;
            while ((bytesRead = input.read(buffer)) != -1) {
                String clientIP = socket.getInetAddress().getHostAddress();
                // todo 测试
//                if(true){
//                    clientIP="192.168.5.39";
//                }
                byte[] readByte = new byte[bytesRead];
                System.arraycopy(buffer, 0, readByte, 0, bytesRead);
                String cardInfo = DatatypeConverter.printHexBinary(readByte);

                int timeoutMs=3000;
                IntByReference hComm = new IntByReference();
                CLibrary.INSTANCE.OpenNetConnection(hComm,clientIP , 8000,timeoutMs);
                NetInfo info=new NetInfo();
                CLibrary.INSTANCE.GetNetInfo( hComm.getValue(),info);
                String macAddress = byteToMacAddressString(info.getMAC());
                //todo 暂时注释
                //System.out.println("old:"+cardInfo);
                cardInfo= EStringUtil.convertHexToString(cardInfo);
                System.out.println("Received data : "+clientIP +" : Mac地址:"+byteToMacAddressString(info.getMAC())+"   卡号:"+ cardInfo);
                //异步调用写入
                if(cardInfo!=null && cardInfo.length()>=2 &&CHECK_HEADER.equalsIgnoreCase(cardInfo.substring(0,2))){
                    System.out.println(jishu);
                    jishu++;
                    deviceService.saveCardRecord(macAddress,cardInfo,clientIP);
                }
                CLibrary.INSTANCE.CloseDevice(hComm.getValue());
            }
        } catch (IOException ex) {
            System.err.println("异常: " + ex.getMessage());
        }catch (Error ex) {
            System.err.println("错误: " + ex.getMessage());
        }*//* finally {
            try {
                socket.close();
                System.out.println("Client ex success.");
            } catch (IOException ex) {
                System.err.println("Error closing socket: " + ex.getMessage());
            }
        }*//*
    }*/

    private void handleClient(Socket socket) {
        try (
                InputStream input = socket.getInputStream();
        ) {
            byte[] buffer = new byte[1024]; // 缓冲区
            int bytesRead;
            while ((bytesRead = input.read(buffer)) != -1) {
                String clientIP = socket.getInetAddress().getHostAddress();
                // todo 测试
//                if(true){
//                    clientIP="192.168.5.39";
//                }
                byte[] readByte = new byte[bytesRead];
                System.arraycopy(buffer, 0, readByte, 0, bytesRead);
                log.info("原始数据:{}",readByte);
                String cardInfo = DatatypeConverter.printHexBinary(readByte);
                cardInfo= EStringUtil.convertHexToString(cardInfo);
                log.info("Received data : "+clientIP +" : 卡号:"+ cardInfo);
                //异步调用写入
                if(cardInfo!=null && cardInfo.length()>=2 &&CHECK_HEADER.equalsIgnoreCase(cardInfo.substring(0,2))){
                    System.out.println(jishu);
                    jishu++;
                    deviceService.saveCardRecord(cardInfo,clientIP);
                }
            }
        } catch (IOException ex) {
            System.err.println("异常: " + ex.getMessage());
        }catch (Error ex) {
            System.err.println("错误: " + ex.getMessage());
        }/* finally {
            try {
                socket.close();
                System.out.println("Client ex success.");
            } catch (IOException ex) {
                System.err.println("Error closing socket: " + ex.getMessage());
            }
        }*/
    }

    public static String byteToMacAddressString(byte[] macAddress) {
        // 确保byte数组长度为6
        if (macAddress != null && macAddress.length == 6) {
            // 使用String.format()将byte数组格式化为MAC地址的字符串格式
            return String.format(
                    "%02X:%02X:%02X:%02X:%02X:%02X",
                    macAddress[0], macAddress[1], macAddress[2],
                    macAddress[3], macAddress[4], macAddress[5]
            );
        }
        return null; // 如果byte数组不是6个字节，则返回null或抛出异常
    }
}